/**********************************************************
    COPYRIGHT
        KND, Inc. (c) 2011
    CLASS NAME
        platform_uart.c
    DEPENDENCY

    HISTORY
		08/19/2011, created by Guangxing Liu
**********************************************************/

/*******************INCLUDE******************/
#include "platform_uart.h"
#include "platform_config.h"
#include "LPC177x_8x.h"
#include "platform_timer.h"

volatile platform_uart_buffer * uart0_recv_buffer=NULL;
volatile platform_uart_buffer * uart0_send_buffer=NULL;
volatile platform_uart_buffer * uart1_recv_buffer=NULL;
volatile platform_uart_buffer * uart1_send_buffer=NULL;
volatile platform_uart_buffer * uart2_recv_buffer=NULL;
volatile platform_uart_buffer * uart2_send_buffer=NULL;
volatile platform_uart_buffer * uart3_recv_buffer=NULL;
volatile platform_uart_buffer * uart3_send_buffer=NULL;

volatile platform_uart_baudrate uart_baudrate;

extern volatile platform_timer_counter uart0_timer;
extern volatile platform_timer_counter uart1_timer;
extern volatile platform_timer_counter uart2_timer;
extern volatile platform_timer_counter uart3_timer;

extern int hyacinth_install_device(const char *dev, DeviceInterface *dif);
extern int hyacinth_uninstall_device(const char *dev);

/************************************************************************
	FUNCTION NAME : platform_uart_init
	INPUTS: 
		none
	OUTPUTS:	
		none
	DESCRIPTION:	
		Platform uart value init
************************************************************************/
void platform_uart_init(void)
{

}

/************************************************************************
	FUNCTION NAME : platform_uart_device_open
	INPUTS: 
		none
	OUTPUTS:	
		none
	DESCRIPTION:	
		Uart Device Open
************************************************************************/
DeviceHandle platform_uart_device_open(void)
{
	platform_uart_app_call* handle = (platform_uart_app_call*)malloc(sizeof(platform_uart_app_call));
	if(handle)
	{
		handle->iOpt = Platform_Uart_App_Call_None;
	}
	return (DeviceHandle)handle;
}
/************************************************************************
	FUNCTION NAME : platform_uart_device_close
	INPUTS: 
		DeviceHandle handle
	OUTPUTS:	
		none
	DESCRIPTION:	
		Uart Device Close
************************************************************************/
int platform_uart_device_close(DeviceHandle handle)
{
	platform_uart_app_call* me = (platform_uart_app_call*)handle;
	if(me)
	{
		free(me);
	}
	return 0;
}
/************************************************************************
	FUNCTION NAME : platform_uart_device_ioctl
	INPUTS: 
		DeviceHandle handle, const char *params
	OUTPUTS:	
		none
	DESCRIPTION:	
		Uart Device Control
************************************************************************/
int platform_uart_device_ioctl(DeviceHandle handle, const char *params)
{
	platform_uart_app_call* me = (platform_uart_app_call*)handle;
	
	switch(*params)
	{
		case '0':
			me->iOpt = Platform_Uart_App_Call_SetRecvBuffer;
			return 0;
		case '1':
			me->iOpt = Platform_Uart_App_Call_SetSendBuffer;
			return 0;
		case '2':
			me->iOpt = Platform_Uart_App_Call_ConfigUart;
			return 0;
		default:
			platform_printf("ERROR--platform_uart_device_ioctl unkown params: %s\r\n",params);
			break;
    }

     return -1;
}
/************************************************************************
	FUNCTION NAME :platform_uart_device_read
	INPUTS: 
		DeviceHandle handle, char *buf, int len
	OUTPUTS:	
		none
	DESCRIPTION:	
		Uart Device Read
************************************************************************/
int platform_uart_device_read(DeviceHandle handle, void *buf, int len)
{
	platform_uart_app_call* me = (platform_uart_app_call*)handle;
	
	if(!me)
		return -1;
	switch(me->iOpt)
	{
		case 0:
	         	return 0;
		default:
			platform_printf("ERROR--platform_uart_device_read unkown params: %s\r\n",me->iOpt);
			break;
	}
	
	return -1;
}
/************************************************************************
	FUNCTION NAME : platform_uart_device_write
	INPUTS: 
		DeviceHandle handle,  const char *buf, int len
	OUTPUTS:	
		none
	DESCRIPTION:	
		Uart Device Write
************************************************************************/
int platform_uart_device_write(DeviceHandle handle,  void *buf, int len)
{
	platform_uart_app_call* me = (platform_uart_app_call*)handle;
	
	if(!me || !buf)
		return -1;
	
	switch(me->iOpt)
	{
		case Platform_Uart_App_Call_SetRecvBuffer:
			{
				switch(((platform_uart_buffer*)buf)->uart_port)
				{
					case PORT_UART0:
						uart0_recv_buffer=(platform_uart_buffer*)buf;
						break;
					case PORT_UART1:
						uart1_recv_buffer=(platform_uart_buffer*)buf;
						break;
					case PORT_UART2:
						uart2_recv_buffer=(platform_uart_buffer*)buf;
						break;
					case PORT_UART3:
						uart3_recv_buffer=(platform_uart_buffer*)buf;
						break;
					default:
						return -1;
				}
			}	

			return 0;
		case Platform_Uart_App_Call_SetSendBuffer:
			{
				switch(((platform_uart_buffer*)buf)->uart_port)
				{
					case PORT_UART0:
						uart0_send_buffer=(platform_uart_buffer*)buf;
						break;
					case PORT_UART1:
						uart1_send_buffer=(platform_uart_buffer*)buf;
						break;
					case PORT_UART2:
						uart2_send_buffer=(platform_uart_buffer*)buf;
						break;
					case PORT_UART3:
						uart3_send_buffer=(platform_uart_buffer*)buf;
						break;
					default:
						return -1;
				}
			}
			
			return 0;
		case Platform_Uart_App_Call_ConfigUart:
			{
				platform_uart_config * p_uart_config=NULL;	
				
				LPC_UART_TypeDef *UARTx=NULL;
				
				p_uart_config = (platform_uart_config *)buf;

				switch(p_uart_config->uart_port)
				{
					case PORT_UART0:
						/*
						 * Initialize UART0 pin connect
						 * P0.2: U0_TXD
						 * P0.3: U0_RXD
						 */
						PINSEL_ConfigPin (0, 2, 1);
						
						PINSEL_ConfigPin (0, 3, 1);
						
						UARTx =LPC_UART0;
						
						uart_baudrate.uart0_baudrate = p_uart_config->UARTConfigStruct.Baud_rate;
						
						memset(&uart0_timer,0,sizeof(platform_timer_counter));

						uart0_timer.counter_timeout =( (1000000L*UART_RECV_INTERVAL*8)/(uart_baudrate.uart0_baudrate*BASE_TIME_TICK));
						
						break;
					case PORT_UART1:
						/*
						 * Initialize UART1 pin connect
						 * P3.16: U1_TXD
						 * P3.17: U1_RXD
						 */
						PINSEL_ConfigPin(3,16,3);
						
						PINSEL_ConfigPin(3,17,3);
						
						UARTx =(LPC_UART_TypeDef*)LPC_UART1;
						
						uart_baudrate.uart1_baudrate = p_uart_config->UARTConfigStruct.Baud_rate;

						memset(&uart1_timer,0,sizeof(platform_timer_counter));

						uart1_timer.counter_timeout =( (1000000L*UART_RECV_INTERVAL*8)/(uart_baudrate.uart1_baudrate*BASE_TIME_TICK));

						break;
					case PORT_UART2:
						/*
						 * Initialize UART2 pin connect
						 * P0.10: U2_TXD
						 * P0.11: U2_RXD
						 */
						PINSEL_ConfigPin(0,10,1);
						
						PINSEL_ConfigPin(0,11,1);
						
						UARTx =LPC_UART2;
						
						uart_baudrate.uart2_baudrate = p_uart_config->UARTConfigStruct.Baud_rate;

						memset(&uart2_timer,0,sizeof(platform_timer_counter));

						uart2_timer.counter_timeout =( (1000000L*UART_RECV_INTERVAL*8)/(uart_baudrate.uart2_baudrate*BASE_TIME_TICK));
						break;
					default:
						return -1;
						
				}

				UART_Init(UARTx, &(p_uart_config->UARTConfigStruct));
				UART_TxCmd(UARTx, ENABLE);
				
			}
			return 0;
		default:
			platform_printf("ERROR--platform_uart_device_write unkown params: %s\r\n",me->iOpt);
			break;
	}
	return -1;
}
/************************************************************************
	FUNCTION NAME : platform_init_uart_device
	INPUTS: 
		none
	OUTPUTS:	
		none
	DESCRIPTION:	
		Uart Device Init
************************************************************************/
void platform_init_uart_device(void)
{
	DeviceInterface uart = {
                               platform_uart_device_open,
                               platform_uart_device_close,
                               platform_uart_device_ioctl,
                               platform_uart_device_read,
                               platform_uart_device_write
                              };


	hyacinth_install_device(UART_DEVICE,&uart);
}

/************************************************************************
	FUNCTION NAME : platform_finit_uart_device
	INPUTS: 
		none
	OUTPUTS:	
		none
	DESCRIPTION:	
		Uart Device Finit
************************************************************************/
void platform_finit_uart_device(void)
{
	hyacinth_uninstall_device(UART_DEVICE);
}



/************************************************************************
	FUNCTION NAME : platform_uart_send_data
	INPUTS: 
		unsigned char uart_port
	OUTPUTS:	
		none
	DESCRIPTION:	
		Platform uart send data
************************************************************************/
void platform_uart_send_data(unsigned char uart_port)
{
	switch(uart_port)
	{
		case PORT_UART0:
			if(!uart0_send_buffer) return;
			
			if ((LPC_UART0->LSR & UART_LSR_THRE) && uart0_send_buffer->ready)
			{
				if(uart0_send_buffer->inPos<uart0_send_buffer->length)
				{
					UART_SendByte(LPC_UART0, uart0_send_buffer->pBuffer[uart0_send_buffer->inPos]);
					
					uart0_send_buffer->inPos++;
				}else
				{
					 uart0_send_buffer->ready = FALSE;
					 
					 uart0_send_buffer->finish = TRUE;
				}
			}
			break;
		case PORT_UART1:
			if(!uart1_send_buffer) return;
			
			if ((LPC_UART1->LSR & UART_LSR_THRE) && uart1_send_buffer->ready)
			{
				if(uart1_send_buffer->inPos<uart1_send_buffer->length)
				{
					UART_SendByte((LPC_UART_TypeDef*)LPC_UART1, uart1_send_buffer->pBuffer[uart1_send_buffer->inPos]);
					
					uart1_send_buffer->inPos++;
				}else
				{
					 uart1_send_buffer->ready = FALSE;
					 
					 uart1_send_buffer->finish = TRUE;
				}
			}
			break;
		case PORT_UART2:
			if(!uart2_send_buffer) return;
			
			if ((LPC_UART2->LSR & UART_LSR_THRE) && uart2_send_buffer->ready)
			{
				if(uart2_send_buffer->inPos<uart2_send_buffer->length)
				{
					UART_SendByte(LPC_UART2, uart2_send_buffer->pBuffer[uart2_send_buffer->inPos]);
					
					uart2_send_buffer->inPos++;
				}else
				{
					 uart2_send_buffer->ready = FALSE;
					 
					 uart2_send_buffer->finish = TRUE;
				}
			}
			break;
		case PORT_UART3:
			if(!uart3_send_buffer) return;
			
			if ((LPC_UART3->LSR & UART_LSR_THRE) && uart3_send_buffer->ready)
			{
				if(uart3_send_buffer->inPos<uart3_send_buffer->length)
				{
					UART_SendByte(LPC_UART3, uart3_send_buffer->pBuffer[uart3_send_buffer->inPos]);
					
					uart3_send_buffer->inPos++;
				}else
				{
					 uart3_send_buffer->ready = FALSE;
					 
					 uart3_send_buffer->finish = TRUE;
				}
			}
			break;
		default:
			break;
	}
}

/************************************************************************
	FUNCTION NAME : platform_uart_recv_data
	INPUTS: 
		unsigned char uart_port
	OUTPUTS:	
		none
	DESCRIPTION:	
		Platform uart recv data
************************************************************************/
void platform_uart_recv_data(unsigned char uart_port)
{
	switch(uart_port)
	{
		case PORT_UART0:
			if(!uart0_recv_buffer) return;

			if ((LPC_UART0->LSR & UART_LSR_RDR) && (!uart0_recv_buffer->finish))
			{

				uart0_timer.start = TRUE;

				uart0_timer.counter = 0;
				
				if(uart0_recv_buffer->inPos<BUFFER_SIZE_BM)
				{
					uart0_recv_buffer->pBuffer[uart0_recv_buffer->inPos] = UART_ReceiveByte(LPC_UART0);
					uart0_recv_buffer->inPos++;
					uart0_recv_buffer->length++;
					uart0_recv_buffer->inPos &= BUFFER_SIZE_BM;

					SET_UART_LED;
				}else
				{
					uart0_recv_buffer->finish = TRUE;

					uart0_timer.start = FALSE;

					uart0_timer.counter = 0;

					CLR_UART_LED;
				}
			}
			
			break;
		case PORT_UART1:
			if(!uart1_recv_buffer) return;

			if ((LPC_UART1->LSR & UART_LSR_RDR) && (!uart1_recv_buffer->finish))
			{

				uart1_timer.start = TRUE;

				uart1_timer.counter = 0;
				
				if(uart1_recv_buffer->inPos<BUFFER_SIZE_BM)
				{
					uart1_recv_buffer->pBuffer[uart1_recv_buffer->inPos] = UART_ReceiveByte((LPC_UART_TypeDef* )LPC_UART1);
					uart1_recv_buffer->inPos++;
					uart1_recv_buffer->length++;
					uart1_recv_buffer->inPos &= BUFFER_SIZE_BM;

					SET_UART_LED;
				}else
				{
					uart1_recv_buffer->finish = TRUE;

					uart1_timer.start = FALSE;

					uart1_timer.counter = 0;

					CLR_UART_LED;
				}
			}
			
			break;
		case PORT_UART2:
			if(!uart2_recv_buffer) return;

			if ((LPC_UART2->LSR & UART_LSR_RDR) && (!uart2_recv_buffer->finish))
			{

				uart2_timer.start = TRUE;

				uart2_timer.counter = 0;
				
				if(uart2_recv_buffer->inPos<BUFFER_SIZE_BM)
				{
					uart2_recv_buffer->pBuffer[uart2_recv_buffer->inPos] = UART_ReceiveByte(LPC_UART2);
					uart2_recv_buffer->inPos++;
					uart2_recv_buffer->length++;
					uart2_recv_buffer->inPos &= BUFFER_SIZE_BM;

					SET_UART_LED;
				}else
				{
					uart2_recv_buffer->finish = TRUE;

					uart2_timer.start = FALSE;

					uart2_timer.counter = 0;

					CLR_UART_LED;
				}
			}
			
			break;
		case PORT_UART3:
			if(!uart3_recv_buffer) return;

			if ((LPC_UART3->LSR & UART_LSR_RDR) && (!uart3_recv_buffer->finish))
			{

				uart3_timer.start = TRUE;

				uart3_timer.counter = 0;
				
				if(uart3_recv_buffer->inPos<BUFFER_SIZE_BM)
				{
					uart3_recv_buffer->pBuffer[uart3_recv_buffer->inPos] = UART_ReceiveByte(LPC_UART3);
					uart3_recv_buffer->inPos++;
					uart3_recv_buffer->length++;
					uart3_recv_buffer->inPos &= BUFFER_SIZE_BM;

					SET_UART_LED;
				}else
				{
					uart3_recv_buffer->finish = TRUE;

					uart3_timer.start = FALSE;

					uart3_timer.counter = 0;

					CLR_UART_LED;
				}
			}
			
			break;
		default:
			break;
	}
}

